﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace SemaphoreFuzzy
{
    public partial class Scenario : Form
    {
        private int contadorCarros = 0;
        //private int semaphoreTimeRed = 20000;
        //private int semaphoreTimeGreen = 10000;
        private int semaphoreTimeRed = 2000;
        private int semaphoreTimeGreen = 3000;
        private Queue<Thread> filaThreads = new Queue<Thread>();
        private Queue<PictureBox> filaPictures = new Queue<PictureBox>();

        private int numeroDeCarros = 4; //default

        Point sensorTrafegoCima = new Point(343, 242); //conta os carros que passa na faixa de cima.
        Point sensorTrafegoBaixo = new Point(272, 313); //conta os carros que passam na faixa de baixo.
        Point sinalPointToStop = new Point(550, 0); //ewview it. (posição do semáforo!)
        Point sinalPointToMoveSlowly = new Point(450, 0); //ewview it. (posição do semáforo!)
        Point finalPoint = new Point(978, 0);
        Point startPoint = new Point(-100, 0);
        PictureBox imageNewCar = null;

        Thread t1 = null;
        Thread t2 = null;
        Thread t3 = null;
        Thread t4 = null;
        Thread t5 = null;
        Thread t6 = null;
        Thread newCar = null;

        string sinal = "verde";

        public Scenario()
        {
            InitializeComponent();

            //exibition to the prof.
            this.lblChooseTimeGreen.Visible = false;
            this.lblChooseTimeRed.Visible = false;
            this.txtChooseTimeGreen.Visible = false;
            this.txtChooseTimeRed.Visible = false;
            this.btnChangeTime.Visible = false;
            //end of it.

            t1 = new Thread(StartCar1);
            t2 = new Thread(StartCar2);
            t3 = new Thread(StartCar3);
            t4 = new Thread(StartCar4);
            t5 = new Thread(StartSemaphore);
            t6 = new Thread(Clock);
        }

        // fazendo o carro se deslocar na pista.
        private void FastRun(PictureBox car)
        {
            Point inicialPoint = car.Location;
            //int x = 0;

            while (true)
            {
                //sinal verde; andar livremente.
                while ((this.sinal == "verde"))
                {
                    Thread.Sleep(20);
                    car.Location = new Point(inicialPoint.X + 1, inicialPoint.Y);
                    inicialPoint = car.Location;
                    //x++;
                    ContadorTrafego(car.Location);

                    //Trecho de código que verifica se o carro chegou ao fim do cenário.
                    //Se ele estiver no final do cenário, o carro volta para o início da pista para manter o fluxo ativo.
                    if (inicialPoint.X == finalPoint.X)
                    {
                        inicialPoint.X = startPoint.X;
                    }
                }

                // quando o semáforo não for verde...
                if (inicialPoint.X != sinalPointToStop.X)
                {
                    //se ele estiver compreendido entre um trecho de pista próximo do semáforo, como o sinal não é verde,
                    //o carro andará mais devagar.
                    if ((inicialPoint.X > sinalPointToMoveSlowly.X) && (inicialPoint.X < sinalPointToStop.X))
                    {
                        Thread.Sleep(80);
                        car.Location = new Point(inicialPoint.X + 1, inicialPoint.Y);
                        inicialPoint = car.Location;
                        //x++;
                        ContadorTrafego(car.Location);

                        //Trecho de código que verifica se o carro chegou ao fim do cenário.
                        //Se ele estiver no final do cenário, o carro volta para o início da pista para manter o fluxo ativo.
                        if (inicialPoint.X == finalPoint.X)
                        {
                            inicialPoint.X = startPoint.X;
                        }
                    }
                    else
                    {
                        //caso contrário, continua andando rápido...
                        Thread.Sleep(20);
                        car.Location = new Point(inicialPoint.X + 1, inicialPoint.Y);
                        inicialPoint = car.Location;
                        //x++;
                        ContadorTrafego(car.Location);

                        //Trecho de código que verifica se o carro chegou ao fim do cenário.
                        //Se ele estiver no final do cenário, o carro volta para o início da pista para manter o fluxo ativo.
                        if (inicialPoint.X == finalPoint.X)
                        {
                            inicialPoint.X = startPoint.X;
                        }
                    }
                }
            }
        }

        private void SemaphoreAction()
        {
            while (true)
            {
                //inicia os valores default do semáforo.
                int tempoVerde = this.semaphoreTimeGreen;
                int tempoVermelho = this.semaphoreTimeRed;

                this.sinal = "verde";
                Thread.Sleep(tempoVerde);
            
                this.pkbSinal.Image = global::SemaphoreFuzzy.Properties.Resources.sinalA;
                this.sinal = "amarelo";
                Thread.Sleep(2000);
                this.pkbSinal.Image = global::SemaphoreFuzzy.Properties.Resources.sinalVERMELHO;
            
                this.sinal = "vermelho";
                Thread.Sleep(tempoVermelho);
                this.pkbSinal.Image = global::SemaphoreFuzzy.Properties.Resources.sinalVERDE1;
                this.sinal = "verde";
            }
        }

        private void ClockTimer()
        {
            while (true)
            {
                Thread.Sleep(60000);
                SensorTrafego();
                this.contadorCarros = 0;
            }
        }

        private void SensorTrafego()
        {
            //quantidade de carros x minuto. (para teste usamos 20 seg)
            //decimal sensor = numeroDeCarros;
            lblTestCars.Text = contadorCarros.ToString();
        }

        private void StartCar1() { FastRun(this.pbxCar); }
        private void StartCar2() { FastRun(this.pbxCar2); }
        private void StartCar3() { FastRun(this.pbxCar3); }
        private void StartCar4() { FastRun(this.pbxCar4); }
        private void StartDynamicCar() { FastRun(this.imageNewCar); }
        private void StartSemaphore() { SemaphoreAction(); }
        private void Clock() { ClockTimer(); }

        private void btnRestart_Click(object sender, EventArgs e)
        {
            //iniciando a thread do semáforo.
            t5.Start();
            //iniciando a thread do timer.
            t6.Start();
            //iniciando as threads dos carros (4 carros fixos no programa).
            t1.Start(); 
            t2.Start();
            t3.Start();
            t4.Start();
        }

        private void btnChangeTime_Click(object sender, EventArgs e)
        {
            //definindo um novo valor para o tempo do semáforo quando ele está verde.
            this.semaphoreTimeGreen = this.txtChooseTimeGreen.Text != string.Empty ? (Convert.ToInt32(this.txtChooseTimeGreen.Text) * 1000) : this.semaphoreTimeGreen;
            //definindo um novo valor para o tempo do semáforo quando ele está vermelho.
            this.semaphoreTimeRed = this.txtChooseTimeRed.Text != string.Empty ? (Convert.ToInt32(this.txtChooseTimeRed.Text) * 1000) : this.semaphoreTimeRed;
        }

        private void btnIncremento_Click(object sender, EventArgs e)
        {
            //incremento no número de carros
            this.numeroDeCarros++;

            //criando um novo carro
            imageNewCar = new PictureBox();
            imageNewCar.BackColor = System.Drawing.Color.Transparent;
            imageNewCar.Image = global::SemaphoreFuzzy.Properties.Resources.onlycar1;
            imageNewCar.Name = "pbxCar" + this.numeroDeCarros;
            imageNewCar.Size = new System.Drawing.Size(100, 65);
            if (numeroDeCarros % 2 == 0)
            {
                imageNewCar.Location = new System.Drawing.Point(2, 242);
            }
            else
            {
                imageNewCar.Location = new System.Drawing.Point(2, 313);
            }

            this.Controls.Add(imageNewCar); //adicionando a imagem do carro no cenário.
            imageNewCar.BringToFront();
            filaPictures.Enqueue(imageNewCar); //a imagem criada é colocada numa fila.

            newCar = new Thread(StartDynamicCar);
            filaThreads.Enqueue(newCar); //a thread criada é colocada numa fila
            newCar.Start(); // iniciando a thread.
        }

        private void btnDecremento_Click(object sender, EventArgs e)
        {
            //removendo um carro do cenário caso a fila tenha algum.
            if (filaThreads.Count > 0)
            {
                Thread thread = filaThreads.Dequeue(); //desenfileirando uma thread.
                PictureBox picture = filaPictures.Dequeue(); //desenfileirando uma thread.

                thread.Suspend(); //suspendendo uma thread.
                this.Controls.Remove(picture); //removendo a imagem do programa.
            }
        }

        private void ContadorTrafego(Point currentPoint)
        {
            if ((currentPoint.Y == sensorTrafegoCima.Y && currentPoint.X == sensorTrafegoCima.X) || (currentPoint.Y == sensorTrafegoBaixo.Y && currentPoint.X == sensorTrafegoBaixo.X))
            {
                this.contadorCarros++;
                //this.lblTestCars.Text = contadorCarros.ToString();
            }
        }
    }
}
